<template>
  <div class="diagram-wrapper">
    <div ref="paperContainer" class="paper-container"></div>
  </div>
</template>

<script setup>
import { onMounted, ref, watch, onBeforeUnmount } from "vue";
import { dia, shapes, util } from "@joint/core";
import GraphUtils from "./utils/diagramUtils";
import { paperMove } from "./utils/paperMove";

const props = defineProps({
  nodes: {
    type: Array,
    default: () => []
  },
  waterSourceVi: {
    type: Number,
    default: 150
  },
  leakageVi: {
    type: Number,
    default: 0
  }
});

const paperContainer = ref(null);
let graph = null;
let paper = null;
let graphUtils = null;

// 格式化数字为两位小数的函数
const formatNumber = (num) => {
  return Number(num).toFixed(2);
};

const calculateTotals = (nodes) => {
  const totals = nodes.reduce((acc, node) => {
    return {
      totalConsumption: acc.totalConsumption + node.vco,
      totalDrainage: acc.totalDrainage + node.vd
    };
  }, { totalConsumption: 0, totalDrainage: 0 });
  // 格式化结果为两位小数
  return {
    totalConsumption: Number(totals.totalConsumption).toFixed(2),
    totalDrainage: Number(totals.totalDrainage).toFixed(2)
  };
};

const resizePaper = () => {
  if (!paper || !paperContainer.value) return;

  const container = paperContainer.value;
  const containerBounds = container.getBoundingClientRect();

  paper.setDimensions(containerBounds.width, containerBounds.height);

  paper.scaleContentToFit({
    padding: 20,
    minScaleX: 0.1,
    minScaleY: 0.1,
    maxScaleX: 2,
    maxScaleY: 2
  });
};

const renderDiagram = () => {
  if (!paperContainer.value) return;

  if (graph) {
    graph.clear();
  }

  const namespace = shapes;
  graph = new dia.Graph({}, { cellNamespace: namespace });
  graphUtils = new GraphUtils(graph);

  paper = new dia.Paper({
    el: paperContainer.value,
    model: graph,
    width: '100%',
    height: '100%',
    cellViewNamespace: namespace,
    linkConnectionPoint: util.shapePerimeterConnectionPoint,
    defaultConnector: {
      name: 'manhattan',
    },
    interactive: {
      vertexAdd: false
    },
    dragPaper: true,
    restrictTranslate: false,
    background: {
      color: '#fff'
    },
    gridSize: 5,
    drawGrid: true
  });

  paperMove(paper)

  const centerX = 560;

  const centerNode = graphUtils.createNode({ label: "水源自来水" }, centerX - 60, 400, 120, 40);

  const waterSourceViLabel = new shapes.standard.Rectangle({
    position: { x: centerX - 60, y: 450 },
    size: { width: 120, height: 20 },
    attrs: {
      body: {
        fill: 'transparent',
        stroke: 'none'
      },
      label: {
        text: `Vi ${formatNumber(props.waterSourceVi)}`,
        fill: '#333',
        fontSize: 16,
        textAnchor: 'middle',
        textVerticalAnchor: 'middle'
      }
    }
  });
  graph.addCell(waterSourceViLabel);

  const govText = new shapes.standard.Rectangle({
    position: { x: centerX - 60, y: 300 },
    size: { width: 120, height: 30 },
    attrs: {
      body: {
        fill: 'transparent',
        stroke: 'none'
      },
      label: {
        text: '市政管网',
        fill: '#000',
        fontSize: 20,
        textAnchor: 'middle',
        textVerticalAnchor: 'middle'
      }
    }
  });
  graph.addCell(govText);

  const link = new shapes.standard.Link({
    router: { name: 'manhattan' },
    connector: { name: 'normal' },
    source: { id: govText.id },
    target: { id: centerNode.id },
    attrs: {
      line: {
        stroke: '#333',
        strokeWidth: 1,
        targetMarker: {
          type: 'path',
          d: 'M 10 -5 0 0 10 5 Z'
        }
      }
    }
  });
  link.addTo(graph);

  const nodeCount = props.nodes.length;
  const leftCount = Math.ceil(nodeCount / 2);
  const leftNodes = props.nodes.slice(0, leftCount);
  const rightNodes = props.nodes.slice(leftCount);

  if (!rightNodes.some(node => node.label === '漏损水')) {
    rightNodes.push({ label: '漏损水', vi: props.leakageVi });
  }

  const paperHeight = 600;
  const verticalPadding = 80;
  const availableHeight = paperHeight - (2 * verticalPadding);

  const minNodeSpacing = 60;
  const leftSpacing = Math.max(availableHeight / (leftNodes.length + 1), minNodeSpacing);
  const rightSpacing = Math.max(availableHeight / (rightNodes.length + 1), minNodeSpacing);

  const leftStartY = verticalPadding;
  const rightStartY = verticalPadding;

  // Left nodes
  const leftElements = leftNodes.map((node, index) => {
    return graphUtils.createNode(
      {
        ...node,
        vi: formatNumber(node.vi),
        vco: formatNumber(node.vco),
        vd: formatNumber(node.vd)
      },
      centerX - 400,
      leftStartY + (index + 1) * leftSpacing,
      100,
      50,
      'left'
    );
  });

  // Right nodes
  const rightElements = rightNodes.map((node, index) => {
    if (node.label === '漏损水') {
      const leakageNode = graphUtils.createLeakageNode(
        '漏损水',
        formatNumber(props.leakageVi),
        centerX + 300,
        rightStartY + (index + 1) * rightSpacing
      );
      graph.addCell(leakageNode);
      return leakageNode;
    }
    return graphUtils.createNode(
      {
        ...node,
        vi: formatNumber(node.vi),
        vco: formatNumber(node.vco),
        vd: formatNumber(node.vd)
      },
      centerX + 300,
      rightStartY + (index + 1) * rightSpacing,
      100,
      50,
      'right'
    );
  });

  const { totalConsumption, totalDrainage } = calculateTotals(props.nodes);
  console.log(totalConsumption, totalDrainage);

  const bottomStartY = Math.max(
    leftStartY + (leftNodes.length * leftSpacing),
    rightStartY + (rightNodes.length * rightSpacing)
  ) + 20;

  const drainageNode = graphUtils.createNode(
    { label: "排水量" },
    centerX - 200,
    bottomStartY + 100,
    100,
    50
  );

  const consumptionNode = graphUtils.createNode(
    { label: "耗水量" },
    centerX + 100,
    bottomStartY + 100,
    100,
    50
  );

  const drainageTotal = new shapes.standard.Rectangle({
    position: { x: centerX - 200, y: bottomStartY + 160 },
    size: { width: 100, height: 20 },
    attrs: {
      body: {
        fill: 'transparent',
        stroke: 'none'
      },
      label: {
        text: `Vd总 ${formatNumber(totalDrainage)}`,
        fill: '#333',
        fontSize: 16,
      }
    }
  });
  graph.addCell(drainageTotal);

  const consumptionTotal = new shapes.standard.Rectangle({
    position: { x: centerX + 100, y: bottomStartY + 160 },
    size: { width: 100, height: 20 },
    attrs: {
      body: {
        fill: 'transparent',
        stroke: 'none'
      },
      label: {
        text: `Vco总 ${formatNumber(totalConsumption)}`,
        fill: '#333',
        fontSize: 16,
      }
    }
  });
  graph.addCell(consumptionTotal);

  // Create connections
  leftNodes.forEach((data, index) => {
    graphUtils.createLink(centerNode, leftElements[index], true);
  });

  rightNodes.forEach((data, index) => {
    graphUtils.createLink(centerNode, rightElements[index], false);
  });

  // Create consumption and drainage links
  [...leftElements, ...rightElements].forEach(element => {
    if (element.attributes.label !== '漏损水') {
      graphUtils.createConsumptionLink(element, consumptionNode, bottomStartY);
      graphUtils.createDrainageLink(element, drainageNode, bottomStartY);
    }
  });

  const bottomFormulaY = bottomStartY + 200;

  // 创建公式文本
  const formulaText = new shapes.standard.Rectangle({
    position: { x: centerX - 300, y: bottomFormulaY },
    size: { width: 600, height: 30 },
    attrs: {
      body: {
        fill: 'transparent',
        stroke: 'none'
      },
      label: {
        text: `取水量 = 排水量 + 耗水量 + 漏损水量`,
        fill: '#333',
        fontSize: 16,
        textAnchor: 'middle',
        textVerticalAnchor: 'middle',
        fontWeight: 'bold'
      }
    }
  });
  graph.addCell(formulaText);

  // 创建具体数值文本（保留两位小数）
  const valuesText = new shapes.standard.Rectangle({
    position: { x: centerX - 300, y: bottomFormulaY + 40 },
    size: { width: 600, height: 30 },
    attrs: {
      body: {
        fill: 'transparent',
        stroke: 'none'
      },
      label: {
        text: `${formatNumber(props.waterSourceVi)} = ${formatNumber(totalDrainage)} + ${formatNumber(totalConsumption)} + ${formatNumber(props.leakageVi)}`,
        fill: '#333',
        fontSize: 16,
        textAnchor: 'middle',
        textVerticalAnchor: 'middle'
      }
    }
  });
  graph.addCell(valuesText);

  setTimeout(resizePaper, 0);
};

// Debounce function
const debounce = (fn, wait) => {
  let timeoutId = null;
  return (...args) => {
    window.clearTimeout(timeoutId);
    timeoutId = window.setTimeout(() => {
      fn.apply(null, args);
    }, wait);
  };
};

const debouncedResize = debounce(resizePaper, 250);

onMounted(() => {
  renderDiagram();
  window.addEventListener('resize', debouncedResize);
});

onBeforeUnmount(() => {
  window.removeEventListener('resize', debouncedResize);
});

watch(() => props.nodes, () => {
  renderDiagram();
}, { deep: true });

watch(() => props.waterSourceVi, () => {
  renderDiagram();
});

watch(() => props.leakageVi, () => {
  renderDiagram();
});
</script>

<style scoped>
.diagram-wrapper {
  position: relative;
  width: 100%;
  height: 100%;
  overflow: hidden;
}

.paper-container {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background-color: #fff;
}

:deep(.joint-paper) {
  background-color: #fff !important;
}

:deep(.joint-paper svg) {
  width: 100% !important;
  height: 100% !important;
}
</style>